/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_task.h"
#include "ak_clk.h"
#include "ak_htbl.h"

#define _SHTBL_TASK_STACK 		0X100000
#define _SHTBL_TASK_PRI 		90

static 	int 	_gTraceLvl_AkHTbl = TRACELVL_NORMAL;

/* ------------------------------------------------------------------
**	Hash Bucket Exp: GC Process.
**	lazyCnt :  _LRU_TICK_LAZY * Ratio.
**	the Ratio is Judged by the Diff of (LazyTick - Current).
** 	
**	Bucket GC Trigger: 50ms Based.
**	Pool GC Trigger: 100ms Based.
*/
static int 	_SHTblLru_Trigger(_t_hTblLru * pHashTbl){

	
	pHashTbl->current = SLru_TickStep(pHashTbl->current);
	SYS_SEM_B_GIVE(&(pHashTbl->hTblGC.gcWake));
	
	return 0;
}

static 	int 	_SHTblLru_Gc(_t_hTblGc * pHashGc)
{
	_t_hTblLru 	  	* 	pHashTbl;
	_t_sysKLMem 	* 	pKLMem;
	_t_sysLruCt 	* 	pBucket;
	time_t 				expire;
	int 				cHash, bat;
	int				(	*fHeapGC)();
	
	int 	i, flag;
	pHashTbl 	= pHashGc->pHashTbl;
	STask_Attr(&(pHashGc->tAttr));
	STask_SetName("HashTbl_GC");

	cHash 	= 0;
	bat 	= (_rHTBL_BUCKET_MAX/_rHTBL_BUCKET_GC);
	while(1){
		SYS_SEM_B_TAKE(&(pHashGc->gcWake), _WAIT_FOREVER);
		cHash = (cHash + 1)%_rHTBL_BUCKET_GC;
		expire = pHashTbl->current;

		pBucket= &(pHashTbl->buckets[cHash * bat]);
		for(i=0; i<bat; i++, pBucket++){
			pKLMem	= pBucket->klMem;
			flag = SLru_Expire(pBucket, expire, _rHTBL_TICK_LAZY);

			/* Check If need GC */
			if(cHash == 0){
				fHeapGC = pKLMem->fHeapGC;
				if(fHeapGC){
					fHeapGC(pKLMem->mHeap);	
				}
			}
		}
	}

	return 0;
}


/* User should Init the MemHeap, Pass the klMem to the HTable */
int 	SHTblLru_Init(_t_hTblLru * pHashTbl, _t_sysKLMem * pKLMem, _t_sysKLFunc * pKLFunc)
{
	_t_hTblGc 		* 	pHashGc;
	_t_sysLruCt		* 	pBucket;
	
	_t_cbentry 			cbEntry;
	int 				i;
	
	/* Init the Pool */
	if(pHashTbl && pKLMem && pKLFunc){

		/* Init the Hash Buckets */
		pHashTbl->opsWr = 0;
		pHashTbl->opsRd = 0;
		pHashTbl->opsHit= 0;
		pHashTbl->opsMiss=0;

		/* Init the KL Mem & KL Func */
		_KLMEM_ASSIGN(&(pHashTbl->klMem), pKLMem);
		_KLFUNC_ASSIGN(&(pHashTbl->klFunc), pKLFunc);
		
		pBucket = pHashTbl->buckets;
		for(i=0; i<_rHTBL_BUCKET_MAX; i++, pBucket++){
			_SLRU_CT_INIT(pBucket, 
				&(pHashTbl->klMem), &(pHashTbl->klFunc),
				i, 
				&(pHashTbl->current));
		}
		
		/* Init the HashTbl GC */
		pHashGc = &(pHashTbl->hTblGC);
		SYS_SEM_B_INIT(&(pHashGc->gcWake));
		pHashGc->pHashTbl = pHashTbl;
		STASK_CRATE(pHashGc->thread, 
					_SHTBL_TASK_STACK,
					_SHTBL_TASK_PRI,
					_SHTblLru_Gc, 
					pHashGc);
		
		/* Init the Trigger */
		pHashTbl->current=0;
		_CBENTRY_INIT(&cbEntry, _SHTblLru_Trigger, pHashTbl, 0);
		SClk_Add(&cbEntry);
	}

	return 0;
}



/* ------------------------------------------------------------------
**	Si-Looking Up Table.
*/
int 	SHTblSis_Init(_t_hTblSiS * pSiTbl, _t_sysKLFunc * pHC)
{
	int 			i;
	_t_hTblSi_Ent * pBucket;
	
	/* Init the Pool */
	if(	pSiTbl && pHC && (pHC->keyComp)){
		/* Init the Hash Buckets */
		pSiTbl->opsWr = 0;
		pSiTbl->opsRd = 0;
		pSiTbl->opsHit= 0;
		pSiTbl->opsMiss=0;

		pBucket = pSiTbl->buckets;
		for(i=0; i<_sHTBL_BUCKET_MAX; i++, pBucket++){
			_SIENT_INIT(pBucket, i);
		}

		/* Init the HC */
		_KLFUNC_ASSIGN(&(pSiTbl->klFunc), pHC);
		
		return 0;
	}

	return -1;
}


_t_rbnode *  SHTblSis_Add(_t_hTblSiS * pSiTbl, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc	* pHC;
	_t_hTblSi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pSiTbl && pNode){
		pHC = &(pSiTbl->klFunc);
		#if 0
		/* Hash */
		kHash 	= pHC->keyHash(pNode);
		#endif
		iBucket = (iBucket % _sHTBL_BUCKET_MAX);
		pBucket	= pSiTbl->buckets + iBucket;
		
		tRoot = &(pBucket->sTree);
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		tNode = rb_insert(tRoot, pNode, pHC->keyComp); 
		if(tNode){
			rb_replace(tRoot, tNode, pNode);	
		}
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
		
	}
	return tNode;
}


_t_rbnode * SHTblSis_Find(_t_hTblSiS * pSiTbl, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc		* pHC;
	_t_hTblSi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pSiTbl && pNode){
		pHC = &(pSiTbl->klFunc);
		#if 0
		/* Hash */
		kHash 	= pHC->keyHash(pNode);
		#endif
		iBucket 	= (iBucket % _sHTBL_BUCKET_MAX);
		pBucket	= pSiTbl->buckets + iBucket;
		
		tRoot = &(pBucket->sTree);
		SYS_LOCK_RD_TAKE(&(pBucket->lock));
		tNode = rb_find(tRoot, pNode, pHC->keyComp); 
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}
	return tNode;
}


_t_rbnode * SHTblSis_Del(_t_hTblSiS * pSiTbl, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc		* pHC;
	_t_hTblSi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pSiTbl && pNode){
		pHC = &(pSiTbl->klFunc);
		#if 0
		/* Hash */
		kHash 	= pHC->keyHash(pNode);
		#endif
		iBucket = (iBucket % _sHTBL_BUCKET_MAX);
		pBucket	= pSiTbl->buckets + iBucket;
		
		tRoot = &(pBucket->sTree);
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		tNode = rb_find(tRoot, pNode, pHC->keyComp); 
		if(tNode){
			rb_erase(tRoot, tNode);
		}
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}
	return tNode;
}


_t_rbnode * SHTblSis_DelEx(_t_hTblSiS * pSiTbl, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc		* pHC;
	_t_hTblSi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pSiTbl && pNode){
		pHC = &(pSiTbl->klFunc);
		#if 0
		/* Hash */
		kHash 	= pHC->keyHash(pNode);
		#endif
		iBucket = (iBucket % _sHTBL_BUCKET_MAX);
		pBucket	= pSiTbl->buckets + iBucket;
		
		tRoot = &(pBucket->sTree);
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		tNode = rb_find(tRoot, pNode, pHC->keyComp); 
		if(tNode && (tNode == pNode)){
			rb_erase(tRoot, tNode);
		}else{
			SYS_TRACE(_gTraceLvl_AkHTbl, TRACELVL_WARNING, "TblSis Del (%p): Dup (%p)?\n", pNode, tNode);
		}
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}
	return tNode;
}

/* ------------------------------------------------------------------
**	Bi-Looking Up Table.
*/
int 	SHTblBis_Init(_t_hTblBiS * pBiTbl, _t_sysKLFunc * pHC_Up, _t_sysKLFunc * pHC_Dn)
{
	int 			i;
	_t_hTblBi_Ent * pBucket;
	
	/* Init the Pool */
	if(	pBiTbl && pHC_Up && pHC_Dn && 
		(pHC_Up->keyComp) && (pHC_Dn->keyComp)	){

		/* Init the Hash Buckets */
		pBiTbl->opsWr = 0;
		pBiTbl->opsRd = 0;
		pBiTbl->opsHit= 0;
		pBiTbl->opsMiss=0;

		pBucket = pBiTbl->buckets;
		for(i=0; i<_bHTBL_BUCKET_MAX; i++, pBucket++){
			_BIENT_INIT(pBucket, i);
		}

		/* Init the HC */
		_KLFUNC_ASSIGN(&(pBiTbl->uHC), pHC_Up);
		_KLFUNC_ASSIGN(&(pBiTbl->dHC), pHC_Dn);
		
		return 0;
	}

	return -1;
}


_t_rbnode *  SHTblBis_Add(_t_hTblBiS * pBiTbl, int type, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc		* pHC;
	_t_hTblBi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pBiTbl && pNode){
		switch(type){
			case _bHTBL_UP:
				/* Hash */
				pHC 	= &(pBiTbl->uHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->uTree);
				break;

			case _bHTBL_DN:
				/* Hash */
				pHC 	= &(pBiTbl->dHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->dTree);
				break;

			default:
				return NULL;
				break;
		}
		
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		tNode = rb_insert(tRoot, pNode, pHC->keyComp); 
		if(tNode){
			rb_replace(tRoot, tNode, pNode);	
		}
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
		
	}
	return tNode;
}


_t_rbnode * SHTblBis_Find(_t_hTblBiS * pBiTbl, int type, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc		* pHC;
	_t_hTblBi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pBiTbl && pNode){
		switch(type){
			case _bHTBL_UP:
				/* Hash */
				pHC 	= &(pBiTbl->uHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->uTree);
				break;

			case _bHTBL_DN:
				/* Hash */
				pHC 	= &(pBiTbl->dHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->dTree);
				break;

			default:
				return NULL;
				break;
		}
		
		SYS_LOCK_RD_TAKE(&(pBucket->lock));
		tNode = rb_find(tRoot, pNode, pHC->keyComp); 
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}
	
	return tNode;
}


_t_rbnode * SHTblBis_Del(_t_hTblBiS * pBiTbl, int type, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc	* pHC;
	_t_hTblBi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pBiTbl && pNode){
		switch(type){
			case _bHTBL_UP:
				/* Hash */
				pHC 	= &(pBiTbl->uHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->uTree);
				break;

			case _bHTBL_DN:
				/* Hash */
				pHC 	= &(pBiTbl->dHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->dTree);
				break;

			default:
				return NULL;
				break;
		}

		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		tNode = rb_find(tRoot, pNode, pHC->keyComp); 
		if(tNode){
			rb_erase(tRoot, tNode);
		}
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}
	return tNode;
}


_t_rbnode * SHTblBis_DelEx(_t_hTblBiS * pBiTbl, int type, _t_rbnode * pNode, unsigned int iBucket)
{
	_t_sysKLFunc	* pHC;
	_t_hTblBi_Ent 	* pBucket;
	_t_rbroot 		* tRoot;
	_t_rbnode 		* tNode;

	tNode = NULL;
	if(pBiTbl && pNode){
		switch(type){
			case _bHTBL_UP:
				/* Hash */
				pHC 	= &(pBiTbl->uHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->uTree);
				break;

			case _bHTBL_DN:
				/* Hash */
				pHC 	= &(pBiTbl->dHC);
				#if 0
				kHash	= pHC->keyHash(pNode);
				#endif
				iBucket	= (iBucket % _bHTBL_BUCKET_MAX);
				pBucket = pBiTbl->buckets + iBucket;
				tRoot = &(pBucket->dTree);
				break;

			default:
				return NULL;
				break;
		}

		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		tNode = rb_find(tRoot, pNode, pHC->keyComp); 
		if(tNode && (tNode == pNode)){
			rb_erase(tRoot, tNode);
		}
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}
	return tNode;
}

/* =====================================================================
**	Add the Support to 2-Level Looking Table.
*/
#define _lHTBL_MEM_PAGE 		0X100000	/* 1M Based */

int 	SHTblLv_Init(_t_hTblLvS * phTblLvS, size_t mLimit)
{
	_t_sysMHeap * pHeap;
	_t_sysMPool * pPool;
	_t_sysMSlot * pSlot;
	_t_hTblLv_Ent*pBucket;
	
	int 		i;
	if(phTblLvS ){
		pHeap = &(phTblLvS->mHeap);
		pPool = &(phTblLvS->mPool);
		pSlot = &(phTblLvS->mSlot);
		
		/* Init the Pool */
		MHeap_Init(pHeap, mLimit);
		MPool_Init(pPool, pHeap,	_lHTBL_MEM_PAGE,	sizeof(_t_hTblLv_Hdl), 
			mLimit/16,	 mLimit/2,	MPOOL_T_SIMP);
		
		/* Init the Slot */
		MPOOL_SET_SLOT(pPool, pSlot);
		MSlot_Init(pSlot, pPool, 0, (unsigned int)(sizeof(_t_hTblLv_Hdl)));

		/* Init the Buckets */
		for(i=0, pBucket=phTblLvS->buckets; i<_lHTBL_BUCKET_MAX; i++, pBucket++){
			_SLENT_INIT(pBucket, i);
		}
		return 0;
	}

	return -1;
}


_t_hTblLv_Hdl *	SHTblLv_PoolAlloc(_t_hTblLvS * phTblLvS)
{
	_t_hTblLv_Hdl	*	pHdl;
	_t_sysMPool 	*	pPool;

	pHdl = NULL;
	if(phTblLvS){
		pPool = &(phTblLvS->mPool);
		pHdl = (_t_hTblLv_Hdl *)MPool_AllocSi(pPool);
		if(pHdl){
			BLIST_INIT(&(pHdl->sQue));
			pHdl->key 	= -1;
			pHdl->type 	= 0;
			pHdl->reserv=0;
			pHdl->pEnt	= NULL;
		}
	}

	return pHdl;
}

int 	SHTblLv_PoolFree(_t_hTblLvS * phTblLvS, _t_hTblLv_Hdl * pHdl)
{
	_t_sysMPool *	pPool;

	if(phTblLvS && pHdl){
		pPool = &(phTblLvS->mPool);
		return	MPool_FreeSi(pPool, pHdl);
	}

	return -1;
}


static 	__inline _t_hTblLv_Hdl * _SHTblLv_TblStep(_t_blist * pQue, int key)
{
	_t_hTblLv_Hdl * pSub;
	_t_hTblLv_Hdl * pHdl;
	long 			i, count;
	
	count	= pQue->count;
	pHdl 	= NULL;
	/* Let's Search for the kPri */
	for(i=0, pSub=(_t_hTblLv_Hdl *)(pQue->next); 
		i<count; 
		i++, pSub=(_t_hTblLv_Hdl *)(pSub->node.next)){
		if(key == pSub->key){
			/* Let's Step Into */
			pHdl = pSub;
			break;
		}
	}

	return pHdl;
}


int 	SHTblLv_TblAdd(_t_hTblLvS * phTblLvS, int * sKey, int nKey, _t_bnode * pNode)
{
	_t_hTblLv_Ent 	* pBucket;
	_t_hTblLv_Hdl  	* pHdl;
	_t_blist 		* pQue;
	int 		 	i, ret, index;
	
	ret 	= -1;
	pHdl	= NULL;
	if(phTblLvS && pNode && (nKey > 0)){
		/* Init */
		index 	= _lHTBL_KEY_GEN(sKey[0]);
		pBucket = phTblLvS->buckets + index;
		pQue 	= &(pBucket->eQue);
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		/* Search Level */
		for(i=0; i<nKey; i++){
			pHdl = _SHTblLv_TblStep(pQue, sKey[i]);
			if(pHdl == NULL){
				for(; i<nKey; i++){
					pHdl = SHTblLv_PoolAlloc(phTblLvS);
					if(!pHdl){
						break;
					}
					/* Assign the Handle */
					pHdl->key = sKey[i];
					pHdl->pEnt= pBucket;
					/* Add to Upper Que */
					BLST_ADD2T(pQue, &(pHdl->node));
					pQue = &(pHdl->sQue);
				}
				
				break;
			}
			else{
				pQue = &(pHdl->sQue);
			}
		}
		
		/* Let's Add the Node */
		if(pHdl){
			BLST_ADD2T(&(pHdl->sQue), pNode);
			ret = 0;
		}
		
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}

	return ret;
}



int 	SHTblLv_TblDel(_t_hTblLvS * phTblLvS, int * sKey, int nKey, _t_bnode * pNode)
{
	_t_hTblLv_Ent 	* pBucket;
	_t_hTblLv_Hdl  	* pHdl;
	_t_blist 		* pQue;
	int 		 	i, ret, index;
	
	ret 	= -1;
	pHdl	= NULL;
	if(phTblLvS && pNode && (nKey > 0)){
		/* Init */
		index 	= _lHTBL_KEY_GEN(sKey[0]);
		pBucket = phTblLvS->buckets + index;
		pQue 	= &(pBucket->eQue);
		
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		/* Search Level */
		for(i=0; i<nKey; i++){
			pHdl = _SHTblLv_TblStep(pQue, sKey[i]);
			if(pHdl == NULL){
				break;
			}else{
				pQue = &(pHdl->sQue);
			}
		}
		if(pHdl){
			/* Let's Del the Node */
			BLST_DEL(&(pHdl->sQue),pNode);
			ret = 0;
		}
		
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}

	return ret;
}



_t_hTblLv_Hdl *	SHTblLv_TblFind(_t_hTblLvS * phTblLvS, int * sKey, int nKey)
{
	_t_hTblLv_Ent 	* pBucket;
	_t_hTblLv_Hdl  	* pHdl;
	_t_blist 		* pQue;
	int 		 	i, index;
	
	pHdl	= NULL;
	if(phTblLvS && (nKey > 0)){
		/* Init */
		index 	= _lHTBL_KEY_GEN(sKey[0]);
		pBucket = phTblLvS->buckets + index;
		pQue 	= &(pBucket->eQue);
		
		SYS_LOCK_RD_TAKE(&(pBucket->lock));
		/* Search Level */
		for(i=0; i<nKey; i++){
			pHdl = _SHTblLv_TblStep(pQue, sKey[i]);
			if(pHdl == NULL){
				break;
			}
			else{
				pQue = &(pHdl->sQue);
			}
		}
		
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}

	return pHdl;
}


_t_hTblLv_Hdl *	SHTblLv_TblSub( _t_hTblLv_Hdl * pHdl, int  idx)
{
	_t_hTblLv_Ent 	* pBucket;
	_t_hTblLv_Hdl  	* pSub;
	_t_blist 		* pQue;
	int 		 	i, count;
	
	pSub	= NULL;
	if(pHdl && (pBucket = pHdl->pEnt)){
		SYS_LOCK_RD_TAKE(&(pBucket->lock));
		pQue 	= &(pHdl->sQue);
		count 	= pQue->count;

		if(idx < count){
			/* Search Level */
			pSub = (_t_hTblLv_Hdl *)(pQue->next);
			for(i=0; i<idx; i++){
				pSub=(_t_hTblLv_Hdl *)(pSub->node.next);
			}
		}
		
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}

	return pSub;
}


int		SHTblLv_TblCursor( _t_hTblLv_Hdl * pHdl,  int  offset,  int num, void ** ppNode)
{
	_t_hTblLv_Ent 	* pBucket;
	_t_hTblLv_Hdl  	* pSub;
	_t_bnode  		* pNode;
	int 		 	i, j, sCnt, hCnt, real;
	
	pSub	= NULL;
	real 	= 0;
	if(pHdl && (pBucket = pHdl->pEnt) && (offset >= 0) && (num > 0) && (ppNode)){
		SYS_LOCK_RD_TAKE(&(pBucket->lock));

		sCnt = pHdl->sQue.count;
		for(i=0; i<sCnt; i++){
			/* Search Level */
			pSub = (_t_hTblLv_Hdl *)(pHdl->sQue.next);

			hCnt = pSub->sQue.count;
			if(hCnt > 0){
				if(offset < hCnt){
					pNode = pSub->sQue.head;
					for(j=0; j<offset; j++){
						pNode=pNode->next;
					}
					do{
						*ppNode = pNode;
						ppNode 	+= 1;
						num 	-= 1;
						j		+= 1;
						real 	+= 1;
						pNode 	= pNode->next;
					}while((j<hCnt) && (num>0));
				}
				else{
					offset -= hCnt;
				}
			}

			if(num <= 0){
				break;
			}
		}
		
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
	}

	return real;
}


/* =====================================================================
**	Add the Support to Casting Looking Table.
*/
int 			SHTblCa_Init(_t_hTblCaS * phTblCaS)
{
	_t_hTblCa_Ent *	pBucket;
	
	int 		i;
	if(phTblCaS ){
		
		/* Init the Buckets */
		for(i=0, pBucket=phTblCaS->buckets; i<_cHTBL_BUCKET_MAX; i++, pBucket++){
			_CAENT_INIT(pBucket, i);
		}
		phTblCaS->opsWr = 0;
		phTblCaS->opsRd = 0;
		return 0;
	}

	return -1;
}


int 	SHTblCa_TblAdd(_t_hTblCaS * phTblCaS, int * sKey, int nKey, _t_bnode * pNode)
{
	_t_hTblCa_Ent 	* pBucket;
	_t_blist 		* pQue;
	int 		 	ret, index;
	
	ret 	= -1;
	if(phTblCaS && pNode && (nKey > 0)){
		/* Init */
		index = _SHTbl_KeyGen(sKey, nKey, _cHTBL_BUCKET_MAX);
		pBucket = phTblCaS->buckets + index;
		pQue 	= &(pBucket->eQue);
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		/* Search Level */
		BLST_ADD2T(pQue,pNode);
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
		ret = 0;
	}

	return ret;
}

int 	SHTblCa_TblDel(_t_hTblCaS * phTblCaS, int * sKey, int nKey, _t_bnode * pNode)
{
	_t_hTblCa_Ent 	* pBucket;
	_t_blist 		* pQue;
	int 		 	ret, index;
	
	ret 	= -1;
	if(phTblCaS && pNode && (nKey > 0)){
		/* Init */
		index = _SHTbl_KeyGen(sKey, nKey, _cHTBL_BUCKET_MAX);
		pBucket = phTblCaS->buckets + index;
		pQue 	= &(pBucket->eQue);
		SYS_LOCK_WR_TAKE(&(pBucket->lock));
		/* Search Level */
		BLST_DEL(pQue,pNode);
		SYS_LOCK_RW_GIVE(&(pBucket->lock));
		ret = 0;
	}

	return ret;
}

